package com.xiaoyy.core.dict.utils;

import com.xiaoyy.core.common.enums.DictType;
import com.xiaoyy.core.common.exception.AppException;
import com.xiaoyy.core.common.vo.SelectVO;
import com.xiaoyy.core.dict.integration.DictIntegration;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author chenzh
 * @date 2019/5/8 22:06
 */
@Service
public class DictUtil {

    /**
     * 转义的字典名称必须以xxxName定义，否则无法自动匹配
     */
    public static final String SUFFIX = "Name";

    @Autowired
    private DictIntegration dictIntegration;

    /**
     * 单个字典校验
     * @param data
     * @param dictType
     * @param <T>
     */
    public <T> void validValue(T data, DictType dictType) {
        validValue(data, Arrays.asList(dictType));
    }

    /**
     * 批量字段校验
     * @param data
     * @param dictTypeList
     * @param <T>
     */
    public <T> void validValue(T data, List<DictType> dictTypeList) {
        if (data == null || CollectionUtils.isEmpty(dictTypeList)) {
            return;
        }
        //查询字典值列表
        Map<String,List<SelectVO>> dictDataVOList = getDictDataList(dictTypeList);
        if (CollectionUtils.isEmpty(dictDataVOList)) {
            return;
        }

        int size = dictDataVOList.size();
        //挨个转义字典值
        for (int i = 0; i < size; i++) {
            DictType dictType = dictTypeList.get(i);
            String property = dictType.getPropertyName();
            String dictKey = getDictValue(data, property);
            if (dictKey == null) {
                continue;
            }
            SelectVO selectVO = filter(dictDataVOList.get(dictType.getPropertyName()), dictKey);
            if (selectVO == null) {
                throw new AppException("无效的[" + dictTypeList.get(i).getFieldName() + "]字典数据");
            }
        }
    }

    /**
     * 单条数据单字典转义
     *
     * @param data
     * @param dictType 字典类型
     * @param <T>
     */
    public <T> void valueToName(T data, DictType dictType) {
        valueToName(Arrays.asList(data), Arrays.asList(dictType));
    }

    /**
     * 单条数据多字典转义
     *
     * @param data
     * @param dictTypeList
     * @param <T>
     */
    public <T> void valueToName(T data, List<DictType> dictTypeList) {
        valueToName(Arrays.asList(data), dictTypeList);
    }

    /**
     * 多条数据单字典转义
     *
     * @param dataList
     * @param dictType
     * @param <T>
     */
    public <T> void valueToName(List<T> dataList, DictType dictType) {
        valueToName(dataList, Arrays.asList(dictType));
    }


    /**
     * 多条数据多字典转义
     *
     * @param dataList     数据列表
     * @param dictTypeList 对应的字典属性列表
     * @param <T>
     */
    public <T> void valueToName(List<T> dataList, List<DictType> dictTypeList) {
        if (CollectionUtils.isEmpty(dataList) || CollectionUtils.isEmpty(dictTypeList)) {
            return;
        }
        //查询字典值列表
        Map<String,List<SelectVO>> dictDataVOList = getDictDataList(dictTypeList);
        if (CollectionUtils.isEmpty(dictDataVOList)) {
            return;
        }

        int size = dictDataVOList.size();
        for (T data : dataList) {
            BeanWrapper beanWrapper = new BeanWrapperImpl(data);
            //挨个转义字典值
            for (int i = 0; i < size; i++) {
                DictType dictType = dictTypeList.get(i);
                String property = dictType.getPropertyName();
                String nameProperty = property + SUFFIX;

                String dictKey = getDictValue(data, property);
                if (dictKey == null) {
                    continue;
                }
                SelectVO dictDataVO = filter(dictDataVOList.get(dictType.getPropertyName()), dictKey);
                if (dictDataVO != null && beanWrapper.isWritableProperty(nameProperty)) {
                    beanWrapper.setPropertyValue(nameProperty, dictDataVO.getDictValue());
                }
            }
        }
    }

    /**
     * 获取字典类型
     *
     * @param dictField
     * @return
     */
    public List<SelectVO> getDictData(String dictField) {
        if (StringUtils.isBlank(dictField)) {
            return null;
        }
        List<SelectVO> result = dictIntegration.getDict(dictField);
        return result;
    }

    /**
     * 根据一组字典类型获取字典值列表
     *
     * @param dictTypeList
     * @return
     */
    private Map<String,List<SelectVO>> getDictDataList(List<DictType> dictTypeList) {
        if (CollectionUtils.isEmpty(dictTypeList)) {
            return new HashMap<>();
        }
        Map<String,List<SelectVO>> map = new HashMap<>();
        for (DictType dictType : dictTypeList) {
            List<SelectVO> result = dictIntegration.getDict(dictType.getDictField().toUpperCase());
            if (!CollectionUtils.isEmpty(result)){
                map.put(dictType.getPropertyName(),result);
            }
        }
        return map;
    }

    /**
     * 获取某个属性的字典值
     *
     * @param data
     * @param property
     * @param <T>
     * @return
     */
    private <T> String getDictValue(T data, String property) {
        BeanWrapper beanWrapper = new BeanWrapperImpl(data);
        //字典属性和字典名称属性必须有效
        if (!beanWrapper.isReadableProperty(property)) {
            return null;
        }
        Object obj = beanWrapper.getPropertyValue(property);
        if (obj == null) {
            return null;
        }
        try {
            return obj.toString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 找到具体的字典对象
     * @param dictDataVOList
     * @param dictKey
     * @return
     */
    private SelectVO filter(List<SelectVO> dictDataVOList, String dictKey) {
        return CollectionUtils.isEmpty(dictDataVOList) ? null : dictDataVOList.stream().filter(dictDataVO ->
                dictDataVO.getDictKey().equals(dictKey)).findFirst().orElse(null);
    }

}
